1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.CollectPreconditions.checkEntryNotNull;
21
22 import com.google.common.annotations.Beta;
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.collect.ImmutableMapEntry.TerminalEntry;
25
26 import java.io.Serializable;
27 import java.util.Collections;
28 import java.util.EnumMap;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.Map;
32
33 import javax.annotation.Nullable;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 @GwtCompatible(serializable = true, emulated = true)
61 @SuppressWarnings("serial")
62 public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
63
64
65
66
67
68
69 public static <K, V> ImmutableMap<K, V> of() {
70 return ImmutableBiMap.of();
71 }
72
73
74
75
76
77
78
79 public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
80 return ImmutableBiMap.of(k1, v1);
81 }
82
83
84
85
86
87
88 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) {
89 return new RegularImmutableMap<K, V>(entryOf(k1, v1), entryOf(k2, v2));
90 }
91
92
93
94
95
96
97 public static <K, V> ImmutableMap<K, V> of(
98 K k1, V v1, K k2, V v2, K k3, V v3) {
99 return new RegularImmutableMap<K, V>(
100 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
101 }
102
103
104
105
106
107
108 public static <K, V> ImmutableMap<K, V> of(
109 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
110 return new RegularImmutableMap<K, V>(
111 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4));
112 }
113
114
115
116
117
118
119 public static <K, V> ImmutableMap<K, V> of(
120 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
121 return new RegularImmutableMap<K, V>(entryOf(k1, v1),
122 entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5));
123 }
124
125
126
127
128
129
130
131
132
133
134 static <K, V> TerminalEntry<K, V> entryOf(K key, V value) {
135 checkEntryNotNull(key, value);
136 return new TerminalEntry<K, V>(key, value);
137 }
138
139
140
141
142
143 public static <K, V> Builder<K, V> builder() {
144 return new Builder<K, V>();
145 }
146
147 static void checkNoConflict(boolean safe, String conflictDescription,
148 Entry<?, ?> entry1, Entry<?, ?> entry2) {
149 if (!safe) {
150 throw new IllegalArgumentException(
151 "Multiple entries with same " + conflictDescription + ": " + entry1 + " and " + entry2);
152 }
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 public static class Builder<K, V> {
176 TerminalEntry<K, V>[] entries;
177 int size;
178
179
180
181
182
183 public Builder() {
184 this(ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY);
185 }
186
187 @SuppressWarnings("unchecked")
188 Builder(int initialCapacity) {
189 this.entries = new TerminalEntry[initialCapacity];
190 this.size = 0;
191 }
192
193 private void ensureCapacity(int minCapacity) {
194 if (minCapacity > entries.length) {
195 entries = ObjectArrays.arraysCopyOf(
196 entries, ImmutableCollection.Builder.expandedCapacity(entries.length, minCapacity));
197 }
198 }
199
200
201
202
203
204 public Builder<K, V> put(K key, V value) {
205 ensureCapacity(size + 1);
206 TerminalEntry<K, V> entry = entryOf(key, value);
207
208 entries[size++] = entry;
209 return this;
210 }
211
212
213
214
215
216
217
218
219 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
220 return put(entry.getKey(), entry.getValue());
221 }
222
223
224
225
226
227
228
229 public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
230 ensureCapacity(size + map.size());
231 for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
232 put(entry);
233 }
234 return this;
235 }
236
237
238
239
240
241
242
243
244
245
246
247 public ImmutableMap<K, V> build() {
248 switch (size) {
249 case 0:
250 return of();
251 case 1:
252 return of(entries[0].getKey(), entries[0].getValue());
253 default:
254 return new RegularImmutableMap<K, V>(size, entries);
255 }
256 }
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271 public static <K, V> ImmutableMap<K, V> copyOf(
272 Map<? extends K, ? extends V> map) {
273 if ((map instanceof ImmutableMap) && !(map instanceof ImmutableSortedMap)) {
274
275
276
277 @SuppressWarnings("unchecked")
278 ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
279 if (!kvMap.isPartialView()) {
280 return kvMap;
281 }
282 } else if (map instanceof EnumMap) {
283 return copyOfEnumMapUnsafe(map);
284 }
285 Entry<?, ?>[] entries = map.entrySet().toArray(EMPTY_ENTRY_ARRAY);
286 switch (entries.length) {
287 case 0:
288 return of();
289 case 1:
290 @SuppressWarnings("unchecked")
291 Entry<K, V> onlyEntry = (Entry<K, V>) entries[0];
292 return of(onlyEntry.getKey(), onlyEntry.getValue());
293 default:
294 return new RegularImmutableMap<K, V>(entries);
295 }
296 }
297
298
299 @SuppressWarnings({"unchecked", "rawtypes"})
300 private static <K, V> ImmutableMap<K, V> copyOfEnumMapUnsafe(Map<? extends K, ? extends V> map) {
301 return copyOfEnumMap((EnumMap) map);
302 }
303
304 private static <K extends Enum<K>, V> ImmutableMap<K, V> copyOfEnumMap(
305 Map<K, ? extends V> original) {
306 EnumMap<K, V> copy = new EnumMap<K, V>(original);
307 for (Map.Entry<?, ?> entry : copy.entrySet()) {
308 checkEntryNotNull(entry.getKey(), entry.getValue());
309 }
310 return ImmutableEnumMap.asImmutable(copy);
311 }
312
313 private static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
314
315 ImmutableMap() {}
316
317
318
319
320
321
322
323 @Deprecated
324 @Override
325 public final V put(K k, V v) {
326 throw new UnsupportedOperationException();
327 }
328
329
330
331
332
333
334
335 @Deprecated
336 @Override
337 public final V remove(Object o) {
338 throw new UnsupportedOperationException();
339 }
340
341
342
343
344
345
346
347 @Deprecated
348 @Override
349 public final void putAll(Map<? extends K, ? extends V> map) {
350 throw new UnsupportedOperationException();
351 }
352
353
354
355
356
357
358
359 @Deprecated
360 @Override
361 public final void clear() {
362 throw new UnsupportedOperationException();
363 }
364
365 @Override
366 public boolean isEmpty() {
367 return size() == 0;
368 }
369
370 @Override
371 public boolean containsKey(@Nullable Object key) {
372 return get(key) != null;
373 }
374
375 @Override
376 public boolean containsValue(@Nullable Object value) {
377 return values().contains(value);
378 }
379
380
381 @Override
382 public abstract V get(@Nullable Object key);
383
384 private transient ImmutableSet<Entry<K, V>> entrySet;
385
386
387
388
389
390 @Override
391 public ImmutableSet<Entry<K, V>> entrySet() {
392 ImmutableSet<Entry<K, V>> result = entrySet;
393 return (result == null) ? entrySet = createEntrySet() : result;
394 }
395
396 abstract ImmutableSet<Entry<K, V>> createEntrySet();
397
398 private transient ImmutableSet<K> keySet;
399
400
401
402
403
404 @Override
405 public ImmutableSet<K> keySet() {
406 ImmutableSet<K> result = keySet;
407 return (result == null) ? keySet = createKeySet() : result;
408 }
409
410 ImmutableSet<K> createKeySet() {
411 return new ImmutableMapKeySet<K, V>(this);
412 }
413
414 private transient ImmutableCollection<V> values;
415
416
417
418
419
420 @Override
421 public ImmutableCollection<V> values() {
422 ImmutableCollection<V> result = values;
423 return (result == null) ? values = new ImmutableMapValues<K, V>(this) : result;
424 }
425
426
427 private transient ImmutableSetMultimap<K, V> multimapView;
428
429
430
431
432
433
434 @Beta
435 public ImmutableSetMultimap<K, V> asMultimap() {
436 ImmutableSetMultimap<K, V> result = multimapView;
437 return (result == null) ? (multimapView = createMultimapView()) : result;
438 }
439
440 private ImmutableSetMultimap<K, V> createMultimapView() {
441 ImmutableMap<K, ImmutableSet<V>> map = viewMapValuesAsSingletonSets();
442 return new ImmutableSetMultimap<K, V>(map, map.size(), null);
443 }
444
445 private ImmutableMap<K, ImmutableSet<V>> viewMapValuesAsSingletonSets() {
446 return new MapViewOfValuesAsSingletonSets<K, V>(this);
447 }
448
449 private static final class MapViewOfValuesAsSingletonSets<K, V>
450 extends ImmutableMap<K, ImmutableSet<V>> {
451 private final ImmutableMap<K, V> delegate;
452
453 MapViewOfValuesAsSingletonSets(ImmutableMap<K, V> delegate) {
454 this.delegate = checkNotNull(delegate);
455 }
456
457 @Override public int size() {
458 return delegate.size();
459 }
460
461 @Override public boolean containsKey(@Nullable Object key) {
462 return delegate.containsKey(key);
463 }
464
465 @Override public ImmutableSet<V> get(@Nullable Object key) {
466 V outerValue = delegate.get(key);
467 return (outerValue == null) ? null : ImmutableSet.of(outerValue);
468 }
469
470 @Override boolean isPartialView() {
471 return false;
472 }
473
474 @Override ImmutableSet<Entry<K, ImmutableSet<V>>> createEntrySet() {
475 return new ImmutableMapEntrySet<K, ImmutableSet<V>>() {
476 @Override ImmutableMap<K, ImmutableSet<V>> map() {
477 return MapViewOfValuesAsSingletonSets.this;
478 }
479
480 @Override
481 public UnmodifiableIterator<Entry<K, ImmutableSet<V>>> iterator() {
482 final Iterator<Entry<K, V>> backingIterator = delegate.entrySet().iterator();
483 return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
484 @Override public boolean hasNext() {
485 return backingIterator.hasNext();
486 }
487
488 @Override public Entry<K, ImmutableSet<V>> next() {
489 final Entry<K, V> backingEntry = backingIterator.next();
490 return new AbstractMapEntry<K, ImmutableSet<V>>() {
491 @Override public K getKey() {
492 return backingEntry.getKey();
493 }
494
495 @Override public ImmutableSet<V> getValue() {
496 return ImmutableSet.of(backingEntry.getValue());
497 }
498 };
499 }
500 };
501 }
502 };
503 }
504 }
505
506 @Override public boolean equals(@Nullable Object object) {
507 return Maps.equalsImpl(this, object);
508 }
509
510 abstract boolean isPartialView();
511
512 @Override public int hashCode() {
513
514
515 return entrySet().hashCode();
516 }
517
518 @Override public String toString() {
519 return Maps.toStringImpl(this);
520 }
521
522
523
524
525
526
527 static class SerializedForm implements Serializable {
528 private final Object[] keys;
529 private final Object[] values;
530 SerializedForm(ImmutableMap<?, ?> map) {
531 keys = new Object[map.size()];
532 values = new Object[map.size()];
533 int i = 0;
534 for (Entry<?, ?> entry : map.entrySet()) {
535 keys[i] = entry.getKey();
536 values[i] = entry.getValue();
537 i++;
538 }
539 }
540 Object readResolve() {
541 Builder<Object, Object> builder = new Builder<Object, Object>();
542 return createMap(builder);
543 }
544 Object createMap(Builder<Object, Object> builder) {
545 for (int i = 0; i < keys.length; i++) {
546 builder.put(keys[i], values[i]);
547 }
548 return builder.build();
549 }
550 private static final long serialVersionUID = 0;
551 }
552
553 Object writeReplace() {
554 return new SerializedForm(this);
555 }
556 }